#include "pw_pbl/Memory.hpp"
#include "pw_pbl/Numbers.hpp"
#include <memory>
#include <type_traits>

namespace pw_pbl
{
	/// 复制位
	/// @param bit_offset 目的位偏移，支持超过8位偏移
	/// @param bits 总位数
	bool copy_bits(const uint8_t *src, Span<uint8_t> tgt, size_t bit_offset, size_t bits)
	{
		constexpr auto CELL_BITS = Math::BitCntOf<uint8_t>;
		if (bits == 0)
			return true;
		if (bit_offset >= CELL_BITS)
		{
			auto [bytes, rem_bits] = std::div((std::make_signed_t<size_t>)bit_offset, CELL_BITS);
			if ((size_t)bytes >= tgt.size())
				return false;
			tgt = {tgt.data() + bytes, tgt.size() - bytes};
		}
		auto bytes = (bit_offset + bits + 0b111) >> 3; // div ceil 8
		if (bytes > tgt.size())
			return false;
		if (bytes < 2)
		{
			auto esrc = src[0];
			auto &etgt = tgt[0];
			auto mask = uint8_t(EMax) >> (CELL_BITS - bits) << bit_offset;
			etgt = (esrc << bit_offset & mask) | (etgt & ~mask);
		}
		else if (bit_offset == 0)
		{
			std::uninitialized_copy_n(src, bytes - 1, tgt.data());
			auto esrc = src[bytes - 1];
			auto &etgt = tgt[bytes - 1];
			auto rem = bits - (bytes - 1) * CELL_BITS;
			etgt = (esrc & uint8_t(EMax) >> (CELL_BITS - rem)) | (etgt & uint8_t(EMax) << rem);
		}
		else
		{
			auto lbits = bit_offset;
			auto hbits = CELL_BITS - lbits;
			auto hmark = uint8_t(EMax) << lbits;
			auto lmark = uint8_t(EMax) >> hbits;
			{
				auto &ftgt = tgt[0];
				ftgt = (ftgt & lmark) | src[0] << lbits;
			}
			for (size_t i = 1; i < bytes - 1; i++)
				tgt[i] = (uint16_t &)src[i - 1] >> hbits;
			{
				auto esrc = (uint16_t &)src[bytes - 2] >> hbits;
				auto &etgt = tgt[bytes - 1];
				auto rem = bits - ((bytes - 2) * CELL_BITS) - hbits;
				if (rem != lbits)
				{
					lmark = uint8_t(EMax) >> (CELL_BITS - rem);
					hmark = uint8_t(EMax) << rem;
				}
				etgt = (esrc & lmark) | (etgt & hmark);
			}
		}
		return true;
	}

} // namespace pw_pbl
